﻿using Common;
using System;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;

namespace CarPCBATest.Procedure
{
    /// <summary>
    /// 电压表
    /// </summary>
    internal class IT6302A
    {
        static string deviceName = "电压表IT6302A";
        //通道1，2 30V 3A; 通道3 5V 3A

        //const string CmdGetVersion = "SYSTem:VERSion?";//这条命令用来查询 SCPI 的版本号。
        const string CmdSetRemote = "SYST:REM"; //这条命令用来设置电源为 PC 控制模式。

        const string CmdGetChlSts = "CHANnel:OUTPut?";
        const string CmdGetChl = "INST:SEL?";
        const string CmdGetCurr = "CURR?";  //读取电流
        const string CmdGetVolt = "VOLT?";  //读取电压
        // 切换通道 INST:SEL CH3 设置当前通道电压 VOLT 5 设置当前通道电流 CURR 2

        const string CmdGetErr = "SYST:ERR?";// 读取错误信息

        const string CmdClearErr = "*CLS";

        //const string CmdSetLocal = "SYSTem:LOCal";  //这条命令用来设置电源为面板控制模式
        static bool connected = false;

        private static readonly object locker = new object();

        static string recvData = null;
        private const string StopCode = "\n";

        static SerialPort serialPort;

        public static void SwitchRemote()
        {
            SendCmd(CmdSetRemote);
            //CheckError();
        }

        public static void SetChannelOutput(int channel, bool value)
        {
            if (channel < 1 | channel > 3)
            {
                throw new Exception($"错误的通道[{channel}]");
            }

            SwitchChannel(channel);
            var chlValue = (value ? 1 : 0);
            SendCmd("CHANnel:OUTPut " + chlValue);
            //CheckError();
            var tmp = SendCmdAndWaitReturn(CmdGetChlSts);
            if (tmp != chlValue.ToString())
            {
                throw new Exception("打开或关闭通道失败");
            }
        }

        /// <summary>
        /// 读取电压
        /// </summary>
        /// <returns> </returns>
        public static double GetVoltage(int channel)
        {
            if (channel < 1 | channel > 3)
            {
                throw new Exception($"错误的通道[{channel}]");
            }
            var recv = SendCmdAndWaitReturn(CmdGetVolt);
            //CheckError();
            return double.Parse(recv);
        }

        /// <summary>
        /// 设置电压
        /// </summary>
        /// <param name="value"> </param>
        public static void SetVoltage(int channel, double value)
        {
            if (channel < 1 | channel > 3)
            {
                throw new Exception($"错误的通道[{channel}]");
            }
            if (channel == 3)
            {
                if (value < 0 | value > 5)
                {
                    throw new Exception($"错误的电压,通道=[{channel}],电压[{value}]");
                }
            }
            else
            {
                if (value < 0 | value > 30)
                {
                    throw new Exception($"错误的电压,通道=[{channel}],电压[{value}]");
                }
            }
            SwitchChannel(channel);
            SendCmd("VOLT " + value);
            //CheckError();
            var tmp = GetVoltage(channel);
            if (tmp != value)
            {
                throw new Exception($"设置电压错误[{value}][{tmp}]");
            }
        }

        /// <summary>
        /// 设置电流上限电流
        /// </summary>
        /// <returns> </returns>
        public static void SetCurrent(int channel, double value)
        {
            if (channel < 1 | channel > 3)
            {
                throw new Exception($"错误的通道[{channel}]");
            }

            if (value < 0 | value > 3)
            {
                throw new Exception($"错误的电流,通道=[{channel}],电流[{value}]");
            }

            SwitchChannel(channel);
            SendCmd("CURR " + value);
            //CheckError();
            var tmp = GetCurrent(channel);
            if (tmp != value)
            {
                throw new Exception($"设置电流错误[{value}][{tmp}]");
            }
        }

        public static double GetCurrent(int channel)
        {
            if (channel < 1 | channel > 3)
            {
                throw new Exception($"错误的通道[{channel}]");
            }
            var recv = SendCmdAndWaitReturn(CmdGetCurr);
            //CheckError();
            return double.Parse(recv);
        }

        private static void SendCmd(string cmd)
        {
            Mylog.Debug($"{deviceName} [{cmd}]");
            serialPort.Write(cmd + StopCode);
        }

        private static string SendCmdAndWaitReturn(string cmd)
        {
            Mylog.Debug($"{deviceName} [{cmd}]");
            recvData = null;
            bool timeOut = false;
            var sendCmd = cmd + StopCode;
            serialPort.Write(sendCmd);

            Task.Run(() =>
            {
                Thread.Sleep(2000);
                timeOut = true;
            });
            while (!timeOut)
            {
                Thread.Sleep(10);
                lock (locker)
                {
                    if (recvData != null)
                    {
                        break;
                    }
                }
            }
            if (timeOut)
            {
                throw new Exception("电压表通信异常");
            }

            return recvData;
        }

        private static void SwitchChannel(int channel)
        {
            if (channel < 1 | channel > 3)
            {
                throw new Exception($"错误的通道[{channel}]");
            }
            SendCmd("INST:SEL CH" + channel);
            //CheckError();
            var recv = SendCmdAndWaitReturn(CmdGetChl);
            //CheckError();
            if (int.Parse(recv[2].ToString()) != channel)
            {
                throw new Exception("切换通道错误");
            }
        }

        private static void CheckError()
        {
            var recv = SendCmdAndWaitReturn(CmdGetErr);
            if (recv[0] != '0')
            {
                throw new Exception(deviceName + "CheckError" + recv);
            }
        }

        public static void Connect()
        {
            if (connected) return;
            try
            {
                serialPort = new SerialPort();
                serialPort.BaudRate = 9600;
                serialPort.PortName = PcbConfigHelper.Load().IT6302APort;

                serialPort.Open();
                serialPort.DataReceived += SerialPort_DataReceived;

                // 设置远程模式
                SwitchRemote();
                // 清除err
                SendCmd(CmdClearErr);

                connected = true;
            }
            catch (Exception)
            {
                throw;
            }
        }

        private static void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            lock (locker)
            {
                recvData = (sender as SerialPort).ReadLine();
            }
            Mylog.Debug($"{deviceName}  [{recvData}]");
        }
    }
}